/*
* Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
* License for more details.
*
* $Id: ircbuffer.cpp 581 2009-05-19 16:40:38Z jpnurmi $
*/

#include "ircbuffer.h"
#include "ircbuffer_p.h"
#include "ircsession.h"
#include <QAbstractSocket>
#include <QEventLoop>
#include <QTimer>
#include <QDebug>

namespace Irc
{
    BufferPrivate::BufferPrivate() :
        q_ptr(0),
        session(0),
        name(),
        encoding(),
        bytesWritten(0)
    {
    }

    /*!
        Constructs a new IRC buffer with \a session as parent.
     */
    Buffer::Buffer(const QByteArray& name, Session* session) : 
        QBuffer(session), d_ptr(new BufferPrivate)
    {
        Q_D(Buffer);
        d->name = name;
        d->q_ptr = this;
        d->session = session;
        open(QIODevice::ReadWrite);
        connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)));
    }

    Buffer::Buffer(const QByteArray& name, Session* session, BufferPrivate& dd) : 
        QBuffer(session), d_ptr(&dd)
    {
        Q_D(Buffer);
        d->name = name;
        d->q_ptr = this;
        d->session = session;
        open(QIODevice::ReadWrite);
        connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)));
    }

    /*!
        Destructs the IRC buffer.
     */
    Buffer::~Buffer()
    {
        Q_D(Buffer);
        delete d;
    }

    /*!
        Returns the buffer name.
     */
    QByteArray Buffer::name() const
    {
        Q_D(const Buffer);
        return d->name;
    }

    /*!
        Returns the session that was used to create this buffer
        object. Initially, it is also the parent object.
     */
    Session* Buffer::session() const
    {
        Q_D(const Buffer);
        return d->session;
    }

    /*!
        Returns the encoding.

        The default value is a null QByteArray.
     */
    QByteArray Buffer::encoding() const
    {
        Q_D(const Buffer);
        if (d->encoding.isNull())
            return d->session->encoding();
        return d->encoding;
    }

    /*!
        Sets the \a encoding.

        See QTextCodec documentation for supported encodings.

        Encoding auto-detection can be turned on by passing a null QByteArray.

        The fallback locale is QTextCodec::codecForLocale().
     */
    void Buffer::setEncoding(const QByteArray& encoding)
    {
        Q_D(Buffer);
        d->encoding = encoding;
    }

    /*!
        \reimp
     */
    bool Buffer::waitForReadyRead(int msecs)
    {
        Q_D(Buffer);
        QEventLoop loop;
        connect(this, SIGNAL(readyRead()), &loop, SLOT(quit()));
        if (msecs >= 0)
            QTimer::singleShot(msecs, &loop, SLOT(quit()));
        loop.exec();
        return d->bytesWritten > 0;
    }

    /*!
        Sends a raw \a message.
     */
    void Buffer::raw(const QByteArray& message)
    {
        if (!session() || !session()->socket())
            return;
        session()->socket()->write(message + "\r\n");
    }

    /*!
        Sends a private \a message.
     */
    void Buffer::message(const QByteArray& message)
    {
        raw("PRIVMSG " + name() + " :" + message);
    }

    /*!
        Sends a \a notice.
     */
    void Buffer::notice(const QByteArray& notice)
    {
        raw("NOTICE " + name() + " :" + notice);
    }

    /*!
        Sends a CTCP \a action.
     */
    void Buffer::ctcpAction(const QByteArray& action)
    {
        raw("PRIVMSG " + name() + " :" + '\x01' + "ACTION" + action + '\x01');
    }

    /*!
        Sends a CTCP \a request.
     */
    void Buffer::ctcpRequest(const QByteArray& request)
    {
        raw("PRIVMSG " + name() + " :" + '\x01' + request + '\x01');
    }

    /*!
        Sends a CTCP \a reply.
     */
    void Buffer::ctcpReply(const QByteArray& reply)
    {
        raw("NOTICE " + name() + " :" + '\x01' + reply + '\x01');
    }

    /*!
        \reimp
     */
    qint64 Buffer::writeData(const char* data, qint64 maxSize)
    {
        Q_D(Buffer);
        QByteArray line = QByteArray::fromRawData(data, maxSize);
        if (d->code != 0)
        {
            void msgNumericMessage(const QByteArray& prefix, uint code, const QByteArray& message);
        }
        else if (!qstrcmp(d->command, "PRIVMSG"))
        {
            QByteArray message = line.mid(line.indexOf(':', 1) + 1);
            if (message.startsWith('\1') && message.endsWith('\1'))
            {
                message.remove(0, 1);
                message.remove(message.length() - 1, 1);

                if (message.startsWith("ACTION "))
                {
                    qDebug() << "ACTION:" << Buffer::name() << d->prefix << message;
                    emit ctcpActionReceived(d->prefix, message.mid(7));
                }
                else
                {
                    // TODO: check params
                    qDebug() << "REQUEST:" << Buffer::name() << d->prefix << message;
                    emit ctcpRequestReceived(d->prefix, message);
                }
            }
            else
            {
                qDebug() << "PRIVMSG:" << Buffer::name() << d->prefix << message;
                emit messageReceived(d->prefix, message);
            }
        }
        else if (!qstrcmp(d->command, "NOTICE"))
        {
            qDebug() << "NOTICE:" << Buffer::name() << d->prefix << line.mid(line.indexOf(':', 1) + 1);
            emit noticeReceived(d->prefix, line.mid(line.indexOf(':', 1) + 1));
        }
        return QBuffer::writeData(data, maxSize);
    }
}

#include "moc_ircbuffer.cpp"
